﻿using System;
using System.IO;
using System.Text;
using System.Threading;
using UtilZ.Dotnet.Ex.Base;
using UtilZ.Dotnet.Ex.Communication.Base;
using UtilZ.Dotnet.Ex.Communication.Net.Base;

namespace UtilZ.Dotnet.Ex.Communication.Net.Ftp
{
    internal class FtpDataTransferUnpacker : UnpackerAbs
    {
        private readonly FtpSession _session;
        private readonly FileStream _stream = null;
        private readonly StreamWriter _streamWriter = null;
        private readonly AutoResetEvent _eventHandler = null;


        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="session">FtpSession</param>
        /// <param name="append">true:追加数据到已存在的文件,文件不存在则创建;false:总是创建新文件,如果旧文件存在则替换</param>
        /// <param name="filePath">文件路径,发送数据时,文件路径为null</param>
        public FtpDataTransferUnpacker(FtpSession session, bool append, string filePath)
        {
            this._session = session;

            if (filePath != null)
            {
                if (append)
                {
                    this._stream = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Read);
                }
                else
                {
                    this._stream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.Read);
                }

                switch (session.DataTransferFormat)
                {
                    case FtpDataTransferFormats.Image:
                        this._streamWriter = new StreamWriter(this._stream);
                        break;
                    case FtpDataTransferFormats.ASCII:
                        this._streamWriter = new StreamWriter(this._stream, Encoding.ASCII);
                        break;
                    case FtpDataTransferFormats.EBCDIC:
                        this._streamWriter = new StreamWriter(this._stream, session.FtpServer.Config.EBCDICEncoding);
                        break;
                    default:
                        ZLog.ZLoger.Warn($"ftp服务端未实现的传输格式类型\"{this._session.DataTransferFormat.ToString()}\"");
                        break;
                }

                this._eventHandler = new AutoResetEvent(false);
            }
        }

        /// <summary>
        /// 对数据进行拆包
        /// </summary>
        /// <param name="unpackerPara">分包参数</param>
        /// <returns>拆包成功的数据长度</returns>
        protected override int PrimitiveUnPackge(IUnpackerPara unpackerPara)
        {
            var np = (TcpUnpackerPara)unpackerPara;
            if (np.DataLength == 0)
            {
                return 0;
            }

            try
            {
                this._stream.Write(np.Buffer, np.Offset, np.DataLength);
                this._stream.Flush();
            }
            catch (Exception ex)
            {
                ZLog.ZLoger.Error(ex);
                this.ReceiveException = ex;
                this.Set();
            }

            return np.DataLength;
        }


        public Exception ReceiveException { get; private set; } = null;

        public void Set()
        {
            if (this._eventHandler != null)
            {
                try
                {
                    this._stream.Close();
                    this._eventHandler.Set();
                }
                catch (ObjectDisposedException)
                {

                }
            }
        }


        public void Wait()
        {
            this._eventHandler.WaitOne();
        }

        protected override void Dispose(bool isDisposing)
        {
            base.Dispose(isDisposing);

            if (this._eventHandler != null)
            {
                this._eventHandler.Dispose();
                this._stream.Close();
            }
        }
    }
}
